package com.zzr.demo.redis.service.impl;

import com.zzr.demo.redis.service.CompactCounterService;
import lombok.extern.slf4j.Slf4j;
import org.omg.CORBA.IMP_LIMIT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;

import java.util.List;

/**
 * @author: xiaomi
 * @date: 2021/10/11
 * @description:
 */
@Slf4j
@Service
public class CompactCounterServiceImpl implements CompactCounterService {

    /**
     * 紧凑计数器
     */
    final String COMPACT_KEY = "compact::counter";
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Override
    public void init(long typeIndex) {
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();

        BitFieldSubCommands bitFieldSubCommands = BitFieldSubCommands.create();
        BitFieldSubCommands.BitFieldSetBuilder set = bitFieldSubCommands.set(BitFieldSubCommands.BitFieldType.UINT_8).valueAt(BitFieldSubCommands.Offset.offset(typeIndex).multipliedByTypeLength());
        BitFieldSubCommands to = set.to(0);

        List<Long> longs = opsForValue.bitField(COMPACT_KEY, to);
        log.info("res:{}", longs.get(0));
    }

    @Override
    public long increase(long typeIndex) {
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();

        BitFieldSubCommands commands = BitFieldSubCommands.create();
        //使用饱和运算：在这一模式下，向上溢出的整数值将被设置为类型的最大值，而向下溢出的整数值则会被设置为类型的最小值。
        BitFieldSubCommands incr = commands.incr(BitFieldSubCommands.BitFieldType.UINT_8).valueAt(BitFieldSubCommands.Offset.offset(typeIndex).multipliedByTypeLength())
                .overflow(BitFieldSubCommands.BitFieldIncrBy.Overflow.SAT).by(1);

        List<Long> longs = opsForValue.bitField(COMPACT_KEY, incr);
        long res = longs.get(0);
        log.info("res:{}", res);
        return res;
    }

    /**
     * 跟 increase 类似，于是不做实现
     *
     * @param typeIndex
     * @return
     */
    @Override
    public long decrease(long typeIndex) {
        throw new NotImplementedException();
    }

    @Override
    public long get(long typeIndex) {
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();

        BitFieldSubCommands commands = BitFieldSubCommands.create();
        //).valueAt(BitFieldSubCommands.Offset.offset(typeIndex).multipliedByTypeLength());
        //BitFieldSubCommands get = commands.get(BitFieldSubCommands.BitFieldType.UINT_8).valueAt(BitFieldSubCommands.Offset.offset(typeIndex).multipliedByTypeLength());
        //NOTEME 参数失效了！offset 不管有木有设置位 type 都是认为 zeroBased ！无法设置成根据 type 的索引
        BitFieldSubCommands get = commands.get(BitFieldSubCommands.BitFieldType.UINT_8).valueAt(BitFieldSubCommands.Offset.offset(typeIndex).multipliedByTypeLength());
        List<Long> longs = opsForValue.bitField(COMPACT_KEY, get);
        log.info("res:{}", longs.get(0));
        return longs.get(0);
    }
}
